﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Toolkit.Web.Resources;

namespace Toolkit.Web.Validation
{
    public class PhoneNumberValidator
    {
        public PhoneNumberValidator(string phoneNumber, string isoCountryCode2)
        {
            if (string.IsNullOrEmpty(isoCountryCode2))
            {
                throw new ArgumentException();
            }

            if (isoCountryCode2.Length != 2)
            {
                throw new ArgumentException("IsoCountryCode2 must be exactly 2 characters in length.");
            }

            PhoneNumber = phoneNumber;
            IsoCountryCode2 = isoCountryCode2;
        }

        public string PhoneNumber
        {
            get;
            private set;
        }

        public string IsoCountryCode2
        {
            get;
            private set;
        }

        /// <summary>
        /// Matches North American phone numbers in common formats including 1-###-###-####, (###) ###-#### ####, ###.###.####, etc.
        /// The three seperators that are supported are dashes, periods, and spaces. It also excepts parenthesis around the area code.
        /// http://blog.stevenlevithan.com/archives/validate-phone-number
        /// </summary>
        protected const string NorthAmericaPhoneNumber = @"^(?:\+?1[-. ]?)?\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})(?:[-. ]?[xX]?([0-9]+))?$";

        /// <summary>
        /// Matches international phone numbers in commonly known formats including +### ## ### ### ####, EPP format +CCC.NNNNNNNNNNxEEEE, etc.
        /// http://blog.stevenlevithan.com/archives/validate-phone-number
        /// </summary>
        protected const string InternationalPhoneNumber = @"^\+?(?:(?:[0-9] ?){6,14}[0-9]$)|(?:[0-9]{1,3}\.[0-9]{4,14}(?:[xX][0-9]+)?$)";

        public string Validate()
        {
            if (string.IsNullOrEmpty(PhoneNumber))
            {
                // Whether this value exists or not should be handled with a RequiredAttribute.
                return null;
            }

            PhoneNumber = PhoneNumber.Trim();

            switch (IsoCountryCode2.ToUpper())
            {
                // United States and Canada.
                case "US":
                case "CA":
                    if (!Regex.IsMatch(PhoneNumber, NorthAmericaPhoneNumber))
                    {
                        return string.Format(Language.Validation_InvalidPhoneNumber_Format, "(###) ###-####");
                    }
                    break;

                // All other countries (or unknown country).
                default:
                    if (!Regex.IsMatch(PhoneNumber, InternationalPhoneNumber))
                    {
                        return string.Format(Language.Validation_InvalidPhoneNumber_Format, "## ### ### ####");
                    }
                    break;
            }

            return null;
        }
    }
}
